home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacWorld 1999 February
/
Macworld (1999-02).dmg
/
Cinema 4D GO demo
/
Gumption Plug-ins
/
Plug-ins
/
Freeware
/
SubMesh
/
SubMesh.cof
Wrap
Text File
|
1998-03-09
|
11KB
|
564 lines
/*
This plugin can be used to selectively subdivide a polygon mesh.
Select the desired region with the Points tool and let 'er rip...
Be sure to use Tools/Structure/Optimise afterwards to remove
redundant points and edges (with 5.003, I can do this automatically)
Send comments, praise, money :-) etc. to:
Jim Hasselbrook
hassel@bellatlantic.net
This software is provided free, AS IS. Feel free to modify it to suit your needs.
*/
var p_alloc, e_alloc, t_alloc, q_alloc;
var p_used, e_used, t_used, q_used;
/*
Calculate the required number of points/triangles/quads up front...
SetXxx() is at least an order of magnitude faster than AddXxx()!
*/
estimate(obj) // this is exact, actually
{
var i, which_case;
var points_selected = FALSE;
var pcount = obj->GetPointCount();
var qcount = obj->GetQuadrangleCount();
var tcount = obj->GetTriangleCount();
p_alloc = pcount; p_used = pcount;
e_alloc = 0; e_used = 0;
q_alloc = 0; q_used = 0;
t_alloc = 0; t_used = 0;
var q = new(Quadrangle);
var t = new(Triangle);
for (i=0; i<qcount; i++)
{
obj->GetQuadrangle(i,q);
which_case = 0;
if (obj->IsPointSelected(q->a)) which_case += 8;
if (obj->IsPointSelected(q->b)) which_case += 4;
if (obj->IsPointSelected(q->c)) which_case += 2;
if (obj->IsPointSelected(q->d)) which_case += 1;
if (which_case > 0)
{
points_selected = TRUE;
}
switch (which_case)
{
// less than two points selected -> no subdivided edges
case 0: // xxxx
case 1: // xxxD
case 2: // xxCx
case 4: // xBxx
case 8: // Axxx
// diagonally opposite points don't define an edge, either
case 5: // xBxD
case 10: // AxCx
e_alloc += 4;
q_alloc += 1;
break;
// two points selected -> one subdivided edge
case 3: // xxCD
case 6: // xBCx
case 9: // AxxD
case 12: // ABxx
p_alloc += 1;
e_alloc += 7;
t_alloc += 3;
break;
// three points selected -> two subdivided edges
case 13: // ABxD
case 7: // xBCD
case 11: // AxCD
case 14: // ABCx
p_alloc += 3;
e_alloc += 11;
q_alloc += 1;
t_alloc += 4;
break;
// all points selected -> four subdivided edges
case 15: // ABCD
p_alloc += 5;
e_alloc += 12;
q_alloc += 4;
break;
}
}
for (i=0; i<tcount; i++)
{
obj->GetTriangle(i,t);
which_case = 0;
if (obj->IsPointSelected(t->a)) which_case += 4;
if (obj->IsPointSelected(t->b)) which_case += 2;
if (obj->IsPointSelected(t->c)) which_case += 1;
if (which_case > 0)
{
points_selected = TRUE;
}
switch (which_case)
{
// less than two points selected -> no subdivided edges
case 0: // xxxx
case 1: // xxC
case 2: // xBx
case 4: // Axx
e_alloc += 3;
t_alloc += 1;
break;
// two points selected -> one subdivided edge
case 3: // xBC
case 5: // AxC
case 6: // ABx
p_alloc += 1;
e_alloc += 5;
t_alloc += 2;
break;
// all points selected -> three subdivided edges
case 7: // ABC
p_alloc += 3;
e_alloc += 9;
t_alloc += 4;
break;
}
}
return points_selected;
}
/*
Create a new polygon object from the existing one; just fill in points and edges
*/
copyPoints(doc,obj)
{
var i, p;
var pcount = obj->GetPointCount();
var newobj = doc->NewPolygonObject(stradd(obj->GetName()," copy"),obj->GetUp(),NULL,p_alloc,e_alloc,t_alloc,q_alloc);
newobj->SetScale(obj->GetScale());
newobj->SetPosition(obj->GetPosition());
newobj->SetRotation(obj->GetRotation());
for (i=0;i<pcount;i++) {
p = obj->GetPoint(i);
newobj->SetPoint(i,p);
}
return newobj;
}
/*
Just in case we've underestimated the number of points/edges/triangles/quads we need...
*/
addPoint(obj,p)
{
if (p_used < p_alloc)
{
obj->SetPoint(p_used,p);
}
else // shouldn't happen
{
if (p_used == p_alloc)
{
println("Need more points!");
}
obj->AddPoint(p);
}
return p_used++;
}
addEdge(obj,a,b)
{
if (e_used < e_alloc)
{
obj->SetEdge(e_used,a,b);
}
else // shouldn't happen
{
if (e_used == e_alloc)
{
println("Need more edges!");
}
obj->AddEdge(a,b);
}
e_used++;
}
addQuadrangle(obj,a,b,c,d)
{
if (q_used < q_alloc)
{
obj->SetQuadrangle(q_used,a,b,c,d);
}
else // shouldn't happen
{
if (q_used == q_alloc)
{
println("Need more quadrangles!");
}
obj->AddQuadrangle(a,b,c,d);
}
q_used++;
}
addTriangle(obj,a,b,c)
{
if (t_used < t_alloc)
{
obj->SetTriangle(t_used,a,b,c);
}
else // shouldn't happen
{
if (t_used == t_alloc)
{
println("Need more triangles!");
}
obj->AddTriangle(a,b,c);
}
t_used++;
}
subdivideQuad0(obj,a,b,c,d) // no subdivided edges
{
addEdge(obj,a,b);
addEdge(obj,b,c);
addEdge(obj,c,d);
addEdge(obj,d,a);
addQuadrangle(obj,a,b,c,d);
}
subdivideQuad1(obj,a,b,c,d) // one subdivided edge
{
var pa = obj->GetPoint(a);
var pb = obj->GetPoint(b);
var pab = (pa+pb)/2.0;
var ab = addPoint(obj,pab);
addEdge(obj,a,ab);
addEdge(obj,ab,b);
addEdge(obj,b,c);
addEdge(obj,c,d);
addEdge(obj,d,a);
addEdge(obj,ab,c);
addEdge(obj,ab,d);
addTriangle(obj,a,ab,d);
addTriangle(obj,ab,c,d);
addTriangle(obj,ab,b,c);
}
subdivideQuad2(obj,a,b,c,d) // two subdivided edges
{
var pa = obj->GetPoint(a);
var pb = obj->GetPoint(b);
var pc = obj->GetPoint(c);
var pd = obj->GetPoint(d);
var pab = (pa+pb)/2.0;
var pbc = (pb+pc)/2.0;
var pmid = (pa+pb+pc+pd)/4.0;
var ab = addPoint(obj,pab);
var bc = addPoint(obj,pbc);
var mid = addPoint(obj,pmid);
addEdge(obj,a,ab);
addEdge(obj,ab,b);
addEdge(obj,b,bc);
addEdge(obj,bc,c);
addEdge(obj,c,d);
addEdge(obj,d,a);
addEdge(obj,ab,mid);
addEdge(obj,bc,mid);
addEdge(obj,c,mid);
addEdge(obj,d,mid);
addEdge(obj,a,mid);
addQuadrangle(obj,ab,b,bc,mid);
addTriangle(obj,a,ab,mid);
addTriangle(obj,bc,c,mid);
addTriangle(obj,c,d,mid);
addTriangle(obj,d,a,mid);
}
subdivideQuad4(obj,a,b,c,d) // four subdivided edges
{
var pa = obj->GetPoint(a);
var pb = obj->GetPoint(b);
var pc = obj->GetPoint(c);
var pd = obj->GetPoint(d);
var pab = (pa+pb)/2.0;
var pbc = (pb+pc)/2.0;
var pcd = (pc+pd)/2.0;
var pda = (pd+pa)/2.0;
var pmid = (pa+pb+pc+pd)/4.0;
var ab = addPoint(obj,pab);
var bc = addPoint(obj,pbc);
var cd = addPoint(obj,pcd);
var da = addPoint(obj,pda);
var mid = addPoint(obj,pmid);
addEdge(obj,a,ab);
addEdge(obj,ab,b);
addEdge(obj,b,bc);
addEdge(obj,bc,c);
addEdge(obj,c,cd);
addEdge(obj,cd,d);
addEdge(obj,d,da);
addEdge(obj,da,a);
addEdge(obj,ab,mid);
addEdge(obj,bc,mid);
addEdge(obj,cd,mid);
addEdge(obj,da,mid);
addQuadrangle(obj,a,ab,mid,da);
addQuadrangle(obj,ab,b,bc,mid);
addQuadrangle(obj,mid,bc,c,cd);
addQuadrangle(obj,da,mid,cd,d);
}
subdivideTri0(obj,a,b,c) // no subdivided edges
{
addEdge(obj,a,b);
addEdge(obj,b,c);
addEdge(obj,c,a);
addTriangle(obj,a,b,c);
}
subdivideTri1(obj,a,b,c) // one subdivided edge
{
var pa = obj->GetPoint(a);
var pb = obj->GetPoint(b);
var pab = (pa+pb)/2.0;
var ab = addPoint(obj,pab);
addEdge(obj,a,ab);
addEdge(obj,ab,b);
addEdge(obj,b,c);
addEdge(obj,c,a);
addEdge(obj,ab,c);
addTriangle(obj,a,ab,c);
addTriangle(obj,ab,b,c);
}
subdivideTri3(obj,a,b,c) // three subdivided edges
{
var pa = obj->GetPoint(a);
var pb = obj->GetPoint(b);
var pc = obj->GetPoint(c);
var pab = (pa+pb)/2.0;
var pbc = (pb+pc)/2.0;
var pca = (pc+pa)/2.0;
var ab = addPoint(obj,pab);
var bc = addPoint(obj,pbc);
var ca = addPoint(obj,pca);
addEdge(obj,a,ab);
addEdge(obj,ab,b);
addEdge(obj,b,bc);
addEdge(obj,bc,c);
addEdge(obj,c,ca);
addEdge(obj,ca,a);
addEdge(obj,ab,bc);
addEdge(obj,bc,ca);
addEdge(obj,ca,ab);
addTriangle(obj,a,ab,ca);
addTriangle(obj,ab,bc,ca);
addTriangle(obj,ab,b,bc);
addTriangle(obj,ca,bc,c);
}
/*
Where the rubber meets the road...
*/
subdivide(doc)
{
var i, which_case;
var a,b,c,d;
var obj=doc->FindFirstActiveObject();
if(!obj || !instanceof(obj, PolygonObject))
{
TextDialog("Must select a polygon object!", DLG_OK);
return;
}
if (!estimate(obj))
{
TextDialog("No points were selected!", DLG_OK);
return;
}
var newobj = copyPoints(doc,obj);
var qcount = obj->GetQuadrangleCount();
var tcount = obj->GetTriangleCount();
var num_faces = qcount+tcount;
var q = new(Quadrangle);
var t = new(Triangle);
for (i=0; i<qcount; i++)
{
obj->GetQuadrangle(i,q);
a = q->a; b = q->b; c = q->c; d = q->d;
which_case = 0;
if (obj->IsPointSelected(a)) which_case += 8;
if (obj->IsPointSelected(b)) which_case += 4;
if (obj->IsPointSelected(c)) which_case += 2;
if (obj->IsPointSelected(d)) which_case += 1;
switch (which_case)
{
// less than two points selected -> no subdivided edges
case 0: // xxxx
case 1: // xxxD
case 2: // xxCx
case 4: // xBxx
case 8: // Axxx
// diagonally opposite points don't define an edge, either
case 5: // xBxD
case 10: // AxCx
subdivideQuad0(newobj,a,b,c,d);
break;
// two points selected -> one subdivided edge
case 3: // xxCD
subdivideQuad1(newobj,c,d,a,b);
break;
case 6: // xBCx
subdivideQuad1(newobj,b,c,d,a);
break;
case 9: // AxxD
subdivideQuad1(newobj,d,a,b,c);
break;
case 12: // ABxx
subdivideQuad1(newobj,a,b,c,d);
break;
// three points selected -> two subdivided edges
case 13: // ABxD
subdivideQuad2(newobj,d,a,b,c);
break;
case 7: // xBCD
subdivideQuad2(newobj,b,c,d,a);
break;
case 11: // AxCD
subdivideQuad2(newobj,c,d,a,b);
break;
case 14: // ABCx
subdivideQuad2(newobj,a,b,c,d);
break;
// all points selected -> four subdivided edges
case 15: // ABCD
subdivideQuad4(newobj,a,b,c,d);
break;
}
StatusSetBar(i*100.0/num_faces, TRUE);
}
for (i=0; i<tcount; i++)
{
obj->GetTriangle(i,t);
a = t->a; b = t->b; c = t->c;
which_case = 0;
if (obj->IsPointSelected(a)) which_case += 4;
if (obj->IsPointSelected(b)) which_case += 2;
if (obj->IsPointSelected(c)) which_case += 1;
switch (which_case)
{
// less than two points selected -> no subdivided edges
case 0: // xxxx
case 1: // xxC
case 2: // xBx
case 4: // Axx
subdivideTri0(newobj,a,b,c);
break;
// two points selected -> one subdivided edge
case 3: // xBC
subdivideTri1(newobj,b,c,a);
break;
case 5: // AxC
subdivideTri1(newobj,c,a,b);
break;
case 6: // ABx
subdivideTri1(newobj,a,b,c);
break;
// all points selected -> three subdivided edges
case 7: // ABC
subdivideTri3(newobj,a,b,c);
break;
}
StatusSetBar((i+qcount)*100.0/num_faces, TRUE);
}
// we will have a lot of redundant points/edges when this is done; Optimise!!!
if (GetC4DVersion() < 5003)
{
TextDialog("Done. Please run Tools/Structure/Optimise before proceeding.", DLG_OK);
}
else
{
newobj->Optimize(TRUE,TRUE,TRUE,TRUE); // I assume this is a 5.003 feature?
}
newobj->UpdateObject();
doc->ActivateObject(newobj);
doc->SendMessage(DOCUMENT_CHANGED);
StatusClear();
}
main()
{
RegisterMenuHook("Subdivide","subdivide");
}